home *** CD-ROM | disk | FTP | other *** search
- #define LIBQBUILD_CORE
- #include "../include/libqbuild.h"
-
- #define NUM_HASH 4096
-
- typedef struct hashvert_s {
- struct hashvert_s *next;
- vec3_t point;
- int num;
- int numplanes; // for corner determination
-
- int planenums[2];
- int numedges;
- } __packed hashvert_t; // 36
-
- /* changed by niels */
- #ifdef DEBUG
- hashvert_t hvertex[MAX_MAP_VERTS]; // 847872
- hashvert_t *hvert_p; // 4
- #endif
-
- int firstmodeledge = 1; // 4
- int firstmodelface; // 4
-
- hashvert_t *hashverts[NUM_HASH]; // 16384
- int c_cornerverts; // 4
- int c_tryedges; // 4
- int subdivides;
- vec3_t hash_min, hash_scale; // 24
- struct surface newcopy_t; // 48
-
- /*
- * a surface has all of the faces that could be drawn on a given plane
- *
- * the outside filling stage can remove some of them so a better bsp can be generated
- *
- */
-
- //============================================================================
-
- /*
- * ===============
- * SubdivideFace
- *
- * If the face is >256 in either texture direction, carve a valid sized
- * piece off and insert the remainder in the next link
- * ===============
- */
- void SubdivideFace(__memBase, register struct visfacet * f, register struct visfacet ** prevptr)
- {
- float mins, maxs;
- vec_t v;
- short int axis;
- int i;
- struct plane plane;
- struct visfacet *front, *back, *next;
- struct texinfo *tex;
-
- // special (non-surface cached) faces don't need subdivision
- tex = &bspMem->texinfo[f->texturenum];
-
- if (tex->flags & TEX_SPECIAL)
- return;
-
- for (axis = 0; axis < 2; axis++) {
- while (1) {
- mins = 9999;
- maxs = -9999;
-
- for (i = 0; i < f->numpoints; i++) {
- v = DotProduct(f->pts[i], tex->vecs[axis]);
- if (v < mins)
- mins = v;
- if (v > maxs)
- maxs = v;
- }
-
- if (maxs - mins <= subdivide_size)
- break;
-
- // split it
- subdivides++;
-
- VectorCopy(tex->vecs[axis], plane.normal);
- v = VectorLength(plane.normal);
- VectorNormalize(plane.normal);
- plane.dist = (mins + subdivide_size - 16) / v;
- next = f->next;
- SplitFace(f, &plane, &front, &back);
- if (!front || !back)
- Error("SubdivideFace: didn't split the polygon");
- *prevptr = back;
- back->next = front;
- front->next = next;
- f = back;
- }
- }
- }
-
- /*
- * ================
- * SubdivideFaces
- * ================
- */
- void SubdivideFaces(__memBase, register struct surface * surfhead)
- {
- struct surface *surf;
- struct visfacet *f, **prevptr;
-
- mprintf("----- SubdivideFaces ---\n");
-
- subdivides = 0;
-
- for (surf = surfhead; surf; surf = surf->next) {
- prevptr = &surf->faces;
- while (1) {
- f = *prevptr;
- if (!f)
- break;
- SubdivideFace(bspMem, f, prevptr);
- f = *prevptr;
- prevptr = &f->next;
- }
- }
-
- mprintf("%i faces added by subdivision\n", subdivides);
-
- }
-
- /*
- * =============================================================================
- *
- * GatherNodeFaces
- *
- * Frees the current node tree and returns a new chain of the surfaces that
- * have inside faces.
- * =============================================================================
- */
-
- void GatherNodeFaces_r(register struct node * node)
- {
- struct visfacet *f, *next;
-
- if (node->planenum != PLANENUM_LEAF) {
- //
- // decision node
- //
- for (f = node->faces; f; f = next) {
- next = f->next;
- if (!f->numpoints) { // face was removed outside
-
- FreeFace(f);
- }
- else {
- f->next = validfaces[f->planenum];
- validfaces[f->planenum] = f;
- }
- }
-
- GatherNodeFaces_r(node->children[0]);
- GatherNodeFaces_r(node->children[1]);
-
- tfree(node);
- }
- else {
- //
- // leaf node
- //
- tfree(node);
- }
- }
-
- /*
- * ================
- * GatherNodeFaces
- *
- * ================
- */
- struct surface *GatherNodeFaces(__memBase, register struct node * headnode)
- {
- struct surface *returnval;
-
- /* added by niels */
- if(!(validfaces = (struct visfacet **)tmalloc(sizeof(struct visfacet *) * bspMem->numbrushplanes)))
- Error("GatherNodeFaces: failed to allocate validfaces\n");
- GatherNodeFaces_r(headnode);
- returnval = BuildSurfaces(bspMem);
- /* added by niels */
- tfree(validfaces);
- return returnval;
- }
-
- //===========================================================================
-
- void InitHash(void)
- {
- vec3_t size;
- vec_t volume;
- vec_t scale;
- int newsize[2];
- short int i;
-
- memset(hashverts, 0, sizeof(hashverts));
-
- for (i = 0; i < 3; i++) {
- hash_min[i] = -8000;
- size[i] = 16000;
- }
-
- volume = size[0] * size[1];
-
- scale = sqrt(volume / NUM_HASH);
-
- newsize[0] = size[0] / scale;
- newsize[1] = size[1] / scale;
-
- hash_scale[0] = newsize[0] / size[0];
- hash_scale[1] = newsize[1] / size[1];
- hash_scale[2] = newsize[1];
-
- /* changed by niels */
- #ifdef DEBUG
- hvert_p = hvertex;
- #endif
- }
-
- unsigned HashVec(register vec3_t vec)
- {
- unsigned h;
-
- h = hash_scale[0] * (vec[0] - hash_min[0]) * hash_scale[2]
- + hash_scale[1] * (vec[1] - hash_min[1]);
- if (h >= NUM_HASH)
- return NUM_HASH - 1;
- return h;
- }
-
- /*
- * =============
- * GetVertex
- * =============
- */
- int GetVertex(__memBase, register vec3_t in, register int planenum)
- {
- int h;
- int i;
- hashvert_t *hv;
- vec3_t vert;
-
- for (i = 0; i < 3; i++) {
- if (fabs(in[i] - rint(in[i])) < 0.001)
- vert[i] = rint(in[i]);
- else
- vert[i] = in[i];
- }
-
- h = HashVec(vert);
-
- for (hv = hashverts[h]; hv; hv = hv->next) {
- if (fabs(hv->point[0] - vert[0]) < POINT_EPSILON
- && fabs(hv->point[1] - vert[1]) < POINT_EPSILON
- && fabs(hv->point[2] - vert[2]) < POINT_EPSILON) {
- hv->numedges++;
- if (hv->numplanes == 3)
- return hv->num; // allready known to be a corner
-
- for (i = 0; i < hv->numplanes; i++)
- if (hv->planenums[i] == planenum)
- return hv->num; // allready know this plane
-
- if (hv->numplanes == 2)
- c_cornerverts++;
- else
- hv->planenums[hv->numplanes] = planenum;
- hv->numplanes++;
- return hv->num;
- }
- }
-
- /* changed by niels */
- //hv = hvert_p;
- if(!(hv = (hashvert_t *)kmalloc(sizeof(hashvert_t))))
- Error("GetVertex: failed to allocate hashvert!\n");
- hv->numedges = 1;
- hv->numplanes = 1;
- hv->planenums[0] = planenum;
- hv->next = hashverts[h];
- hashverts[h] = hv;
- VectorCopy(vert, hv->point);
- if (bspMem->numvertexes == bspMem->max_numvertexes)
- ExpandClusters(bspMem, LUMP_VERTEXES);
- hv->num = bspMem->numvertexes;
- /* changed by niels */
- //hvert_p++;
-
- // emit a vertex
- if (bspMem->numvertexes == bspMem->max_numvertexes)
- ExpandClusters(bspMem, LUMP_VERTEXES);
-
- bspMem->dvertexes[bspMem->numvertexes].point[0] = vert[0];
- bspMem->dvertexes[bspMem->numvertexes].point[1] = vert[1];
- bspMem->dvertexes[bspMem->numvertexes].point[2] = vert[2];
- bspMem->numvertexes++;
-
- return hv->num;
- }
-
- //===========================================================================
-
- /*
- * ==================
- * GetEdge
- *
- * Don't allow four way edges
- * ==================
- */
-
- int GetEdge(__memBase, register vec3_t p1, register vec3_t p2, register struct visfacet * f)
- {
- int v1, v2;
- struct dedge_t *edge;
- int i;
-
- if (!f->contents[0])
- Error("GetEdge: 0 contents");
-
- c_tryedges++;
- v1 = GetVertex(bspMem, p1, f->planenum);
- v2 = GetVertex(bspMem, p2, f->planenum);
- for (i = firstmodeledge; i < bspMem->numedges; i++) {
- edge = &bspMem->dedges[i];
- if (v1 == edge->v[1] && v2 == edge->v[0]
- /* && !edgefaces[i][1] */
- && !bspMem->edgefaces[1][i]
- /* && edgefaces[i][0]->contents[0] == f->contents[0]) { */
- && bspMem->edgefaces[0][i]->contents[0] == f->contents[0]) {
- /* edgefaces[i][1] = f; */
- bspMem->edgefaces[1][i] = f;
- return -i;
- }
- }
-
- // emit an edge
- if (bspMem->numedges == bspMem->max_numedges)
- ExpandClusters(bspMem, LUMP_EDGES);
- edge = &bspMem->dedges[bspMem->numedges];
- bspMem->numedges++;
- edge->v[0] = v1;
- edge->v[1] = v2;
- /*edgefaces[i][0] = f; */
- bspMem->edgefaces[0][i] = f;
-
- return i;
- }
-
- /*
- * ==================
- * FindFaceEdges
- * ==================
- */
- void FindFaceEdges(__memBase, register struct visfacet * face)
- {
- int i;
-
- face->outputnumber = -1;
- if (face->numpoints > MAXEDGES)
- Error("WriteFace: %i points", face->numpoints);
-
- for (i = 0; i < face->numpoints; i++)
- face->edges[i] = GetEdge(bspMem, face->pts[i], face->pts[(i + 1) % face->numpoints], face);
- }
-
- #ifdef DEBUG
- /*
- * =============
- * CheckVertexes
- * // debugging
- * =============
- */
- void CheckVertexes(void)
- {
- int cb, c0, c1, c2, c3;
- hashvert_t *hv;
-
- cb = c0 = c1 = c2 = c3 = 0;
- for (hv = hvertex; hv != hvert_p; hv++) {
- if (hv->numedges < 0 || hv->numedges & 1)
- cb++;
- else if (!hv->numedges)
- c0++;
- else if (hv->numedges == 2)
- c1++;
- else if (hv->numedges == 4)
- c2++;
- else
- c3++;
- }
-
- mprintf("%5i bad edge points\n", cb);
- mprintf("%5i 0 edge points\n", c0);
- mprintf("%5i 2 edge points\n", c1);
- mprintf("%5i 4 edge points\n", c2);
- mprintf("%5i 6+ edge points\n", c3);
- }
-
- /*
- * =============
- * CheckEdges
- * // debugging
- * =============
- */
- void CheckEdges(void)
- {
- struct dedge_t *edge;
- int i;
- struct dvertex_t *d1, *d2;
- struct visfacet *f1, *f2;
- int c_nonconvex;
- int c_multitexture;
-
- c_nonconvex = c_multitexture = 0;
-
- // CheckVertexes ();
-
- for (i = 1; i < bspMem->numedges; i++) {
- edge = &bspMem->dedges[i];
- /* if (!edgefaces[i][1]) { */
- if (!bspMem->edgefaces[1][i]) {
- d1 = &bspMem->dvertexes[edge->v[0]];
- d2 = &bspMem->dvertexes[edge->v[1]];
- mprintf("unshared edge at: ( %g %g %g ) ( %g %g %g )\n", d1->point[0], d1->point[1], d1->point[2], d2->point[0], d2->point[1], d2->point[2]);
- }
- else {
- /* f1 = edgefaces[i][0];*/
- f1 = bspMem->edgefaces[0][i];
- /* f2 = edgefaces[i][1];*/
- f2 = bspMem->edgefaces[1][i];
- if (f1->planeside != f2->planeside)
- continue;
- if (f1->planenum != f2->planenum)
- continue;
-
- // on the same plane, might be discardable
- if (f1->texturenum == f2->texturenum) {
- hvertex[edge->v[0]].numedges -= 2;
- hvertex[edge->v[1]].numedges -= 2;
- c_nonconvex++;
- }
- else
- c_multitexture++;
- }
- }
-
- // mprintf ("%5i edges\n", i);
- // mprintf ("%5i c_nonconvex\n", c_nonconvex);
- // mprintf ("%5i c_multitexture\n", c_multitexture);
- // CheckVertexes ();
- }
- #endif
-
- /*
- * ================
- * MakeFaceEdges_r
- * ================
- */
- void MakeFaceEdges_r(__memBase, register struct node * node)
- {
- struct visfacet *f;
-
- if (node->planenum == PLANENUM_LEAF)
- return;
-
- for (f = node->faces; f; f = f->next)
- FindFaceEdges(bspMem, f);
-
- MakeFaceEdges_r(bspMem, node->children[0]);
- MakeFaceEdges_r(bspMem, node->children[1]);
- }
-
- /*
- * ================
- * MakeFaceEdges
- * ================
- */
- void MakeFaceEdges(__memBase, struct node * headnode)
- {
- mprintf("----- MakeFaceEdges -----\n");
-
- InitHash();
- c_tryedges = 0;
- c_cornerverts = 0;
-
- MakeFaceEdges_r(bspMem, headnode);
-
- // CheckEdges ();
-
- GrowNodeRegions(bspMem, headnode);
-
- firstmodeledge = bspMem->numedges;
- firstmodelface = bspMem->numfaces;
-
- /* added by niels */
- kfree();
- }
-